package pri.hillchen.std.concurrent.chapter5;

import java.util.concurrent.*;

/**
 * Created by hillchen on 2018/2/8.
 */
public class ComputeCacheDemo {
    interface Computable<A,V>{
        V compute(A a) throws InterruptedException;
    }
    class Memoizer<A,V> implements Computable<A,V>{
        private final ConcurrentHashMap<A,Future<V>> computeCache = new ConcurrentHashMap<A, Future<V>>();
        private final Computable<A,V> computable;

        public Memoizer(Computable<A, V> computable) {
            this.computable = computable;
        }

        public V compute(final A a) throws InterruptedException {
            while (true){
                Future<V> future = computeCache.get(a);
                if(null == future){
                    Callable<V> eval = new Callable<V>() {
                        public V call() throws Exception {
                            return computable.compute(a);
                        }
                    };
                    FutureTask<V> futureTask = new FutureTask<V>(eval);
                    future = computeCache.putIfAbsent(a,futureTask);
                    if(future == null){
                        future = futureTask;
                        futureTask.run();
                    }
                }
                try{
                    return future.get();
                }catch (CancellationException e){
                    computeCache.remove(a,future);
                }catch (ExecutionException e){
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
